#include <iostream>
#include <string>
#include <vector>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "Task.hpp"

// void work(int fd)
// {
//     while(true)
//     {
//         sleep(1);
//     }
// }

// void work(int rfd)
// {
//     while (true)
//     {
//         int command = 0;
//         int n = read(rfd, &command, sizeof(command));
//         if (n == sizeof(int))
//         {
//             std::cout << "pid is : " << getpid() << " handler task" << std::endl;
//             ExecuteTask(command);
//         }
//         else if (n == 0)
//         {
//             std::cout << "sub process : " << getpid() << " quit" << std::endl;
//             break;
//         }
//     }
// }
// master信道
class Channel
{
public:
    Channel(int wfd, pid_t id, const std::string &name)
        : _wfd(wfd), _subprocessid(id), _name(name)
    {
    }
    int GetWfd() const { return _wfd; }
    pid_t GetProcessId() const { return _subprocessid; }
    std::string GetName() const { return _name; }
    void CloseChannel()
    {
        close(_wfd);
    }
    void Wait()
    {
        pid_t rid = waitpid(_subprocessid, nullptr, 0);
        if (rid > 0)
        {
            std::cout << "wait " << rid << " success" << std::endl;
        }
    }
    ~Channel()
    {
    }

private:
    int _wfd;            // 写端fd
    pid_t _subprocessid; // 子进程pid
    std::string _name;   // 信道名字
};

// 形参类型和命名规范
// const &: 输出
// & : 输入输出型参数
// * : 输出型参数
// // 创建信道和子进程
// void CreateChannelAndSub(int num, std::vector<Channel> *channels)
// {
//     // Bug
//     for (int i = 0; i < num; i++)
//     {
//         // 1.创建管道
//         int pipefd[2] = {0};
//         int n = pipe(pipefd);
//         // n < 0创建失败
//         if (n < 0)
//             exit(0);

//         // 2.创建子进程
//         pid_t id = fork();

//         // child -- read
//         if (id == 0)
//         {
//             // fix bug
//             if(!channels->empty())
//             {
//                 // 第二次之后，关闭子进程开始创建的写端管道
//                 for(auto &channel : *channels) 
//                     channel.CloseChannel();
//             }
//             // 关闭写端
//             close(pipefd[1]);
//             //
//             work(pipefd[0]);
//             close(pipefd[0]);
//             exit(0);
//         }
//         // 3.构建一个channel名称
//         std::string channel_name = "channel-" + std::to_string(i);
//         // father -- write
//         close(pipefd[0]);
//         channels->push_back(Channel(pipefd[1], id, channel_name));
//     }
// }

// 创建信道和子进程(回调方式)
void CreateChannelAndSub(int num, std::vector<Channel> *channels,task_t task)
{
    // Bug
    for (int i = 0; i < num; i++)
    {
        // 1.创建管道
        int pipefd[2] = {0};
        int n = pipe(pipefd);
        // n < 0创建失败
        if (n < 0)
            exit(0);

        // 2.创建子进程
        pid_t id = fork();

        // child -- read
        if (id == 0)
        {
            // fix bug
            if(!channels->empty())
            {
                // 第二次之后，关闭子进程开始创建的写端管道
                for(auto &channel : *channels) 
                    channel.CloseChannel();
            }
            // 关闭写端
            close(pipefd[1]);
            dup2(pipefd[0], 0); // 将管道的读端，重定向到标准输入
            task();
            close(pipefd[0]);
            exit(0);
        }
        // 3.构建一个channel名称
        std::string channel_name = "channel-" + std::to_string(i);
        // father -- write
        close(pipefd[0]);
        channels->push_back(Channel(pipefd[1], id, channel_name));
    }
}

// 0 1 2 channelnum
int NextChannel(int channelnum)
{
    static int next = 0;
    int channel = next;
    next++;
    next %= channelnum;
    return channel;
}

void SendTaskCommand(const Channel &channel, int taskcommand)
{
    write(channel.GetWfd(), &taskcommand, sizeof(taskcommand));
}

// 控制一次子进程
void ctrlProcessOnce(std::vector<Channel> &channels)
{
    sleep(1);
    // a.选择一个任务
    int taskcommand = SelectTask();
    // b.选择一个信道和进程
    int channel_index = NextChannel(channels.size());
    // c.发送任务
    SendTaskCommand(channels[channel_index], taskcommand);
    std::cout << std::endl;
    std::cout << "taskcommand: " << taskcommand << " channel: "
              << channels[channel_index].GetName() << " sub process: " << channels[channel_index].GetProcessId() << std::endl;
}

// void ctrlProcess(std::vector<Channel> &channels)
// {
//     while (true)
//     {
//         sleep(1);
//         // a.选择一个任务
//         int taskcommand = SelectTask();
//         // b.选择一个信道和进程
//         int channel_index = NextChannel(channels.size());
//         // c.发送任务
//         SendTaskCommand(channels[channel_index], taskcommand);
//         std::cout << std::endl;
//         std::cout << "taskcommand: " << taskcommand << " channel: "
//                   << channels[channel_index].GetName() << " sub process: " << channels[channel_index].GetProcessId() << std::endl;
//     }
// }

void ctrlProcess(std::vector<Channel> &channels, int times = -1)
{
    if (times > 0)
    {
        while (times--)
        {
            ctrlProcessOnce(channels);
        }
    }
    else
    {
        while (true)
        {
            ctrlProcessOnce(channels);
        }
    }
}

void CleanUpChannel(std::vector<Channel> &channels)
{
    // 逆向关闭管道
    int num = channels.size() - 1;
    while(num >=0)
    {
        channels[num].CloseChannel();
        channels[num--].Wait();
    }
    // for (auto &channel : channels)
    // {
    //     channel.CloseChannel();
    //     channel.Wait();
    // }
    // for (auto &channel : channels)
    // {
    //     channel.Wait();
    // }
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        std::cerr << "Usage: " << argv[0] << "processnum" << std::endl;
        return 1;
    }
    int num = std::stoi(argv[1]);
    // 加载任务
    LoadTask();
    std::vector<Channel> channels;
    // 1.创建信道和子进程，普通版本
    //CreateChannelAndSub(num, &channels);
    
    // 1.创建信道和子进程，回调版本，调用什么函数，传什么函数名
    CreateChannelAndSub(num, &channels,work);

    // 2.通过channle控制子进程,执行5次
    ctrlProcess(channels,5);

    // 3. 回收管道和子进程. a. 关闭所有的写端 b. 回收子进程
    CleanUpChannel(channels);
    return 0;
}

// ./processpool 5 测试代码一
// int main(int argc,char* argv[])
// {
//     // 通过命令行传参创建几个子进程，不传个数直接报错
//     if(argc != 2)
//     {
//         std::cerr << "Usage: " << argv[0] << "processnum" << std::endl;
//         return 1;
//     }
//     int num = std::stoi(argv[1]);

//     std::vector<Channel> channels;
//     // 1.创建信道和子进程
//     for(int i = 0;i < num;i++)
//     {
//         // 1.创建管道
//         int pipefd[2] = {0};
//         int n = pipe(pipefd);
//         // n < 0创建失败
//         if(n < 0) exit(0);

//         // 2.创建子进程
//         pid_t id = fork();

//         // child -- read
//         if(id == 0)
//         {
//             // 关闭写端
//             close(pipefd[1]);
//             //
//             work(pipefd[0]);
//             close(pipefd[0]);
//             exit(0);
//         }
//         // 3.构建一个channel名称
//         std::string channel_name = "channel-" + std::to_string(i);
//         // father -- write
//         close(pipefd[0]);
//         channels.push_back(Channel(pipefd[1],id,channel_name));
//     }
//     // for test
//     for(auto& channel : channels)
//     {
//         std::cout << "====================================" << std::endl;
//         std::cout << "channel_name->" << channel.GetName() << std::endl;
//         std::cout << "channel_wfd->" << channel.GetWfd() << std::endl;
//         std::cout << "channel_id->" << channel.GetProcessId() << std::endl;
//     }
//     sleep(100);
//     return 0;
// }